home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / AMScen_0_9.lha / AMScen / machines.m < prev    next >
Text File  |  1995-01-21  |  18KB  |  651 lines

  1. /*
  2.  * Amiga MUD
  3.  *
  4.  * Copyright (c) 1995 by Chris Gray
  5.  */
  6.  
  7. /*
  8.  * machines.m - code to add two simple machines to the world.
  9.  *    NOTE: rooms referenced directly:
  10.  *        r_mallEntrance - 3 times for the entry-exit recorder
  11.  *        r_crossSW - starting point for Caretaker
  12.  *        r_pearField - used in packratStep to force pear picking
  13.  *        r_esEnd - starting point for Packrat
  14.  *    We also reference directly: p_oPlayAction, p_oEraseAction
  15.  *    We also require DoGet and DoDrop from verbs.m
  16.  */
  17.  
  18. use t_streets
  19.  
  20. private tp_machines CreateTable().
  21. use tp_machines
  22.  
  23. /*****************************************************************************\
  24. *                                          *
  25. *   NOTE: This entry-exit recorder should be commented out if the MUD is      *
  26. *    running on a floppy disk. Since it continually modifies its record    *
  27. *    when the automatic machines go by, it is continually creating          *
  28. *    database entries that must be written out, hence there will be          *
  29. *    continual disk I/O even if no-one is playing. A big database cache    *
  30. *    can minimize this effect, but will not stop it completely.          *
  31. *                                          *
  32. \*****************************************************************************/
  33.  
  34. /* first, stuff in the entry-exit recorder (not a true machine) */
  35.  
  36. define tp_machines o_recorder CreateThing(nil).
  37. SetThingStatus(o_recorder, ts_readonly).
  38. SetupObject(o_recorder, r_mallEntrance,
  39.     "machine,player,recorder;enter-exit.machine,player,recorder;enter,exit,"
  40.     "enter-exit.exit;enter",
  41.     "This is a very strange machine. It's purpose, as indicated by a small "
  42.     "instruction label, is to record the comings and goings of people. "
  43.     "It will respond to 'play' and 'erase' to play its current record "
  44.     "and to erase it, respectively.").
  45. define tp_machines p_recorderRecord CreateStringProp().
  46. o_recorder@p_recorderRecord := "".
  47.  
  48. /*
  49.  * recorderEnter - the recorder's player enter action.
  50.  */
  51.  
  52. define tp_machines proc recorderEnter()status:
  53.     string s;
  54.  
  55.     s := o_recorder@p_recorderRecord;
  56.     if Length(s) >= 3500 then
  57.     /* we are obviously pretty busy, and getting close to the current
  58.        arbitrary string maximum of 4K, so just nuke the record. */
  59.     s := "";
  60.     else
  61.     s := s + "    " + FormatName(Me()@p_pName) + " arrived.\n";
  62.     fi;
  63.     o_recorder@p_recorderRecord := s;
  64.     continue
  65. corp;
  66.  
  67. /*
  68.  * recorderLeave - the recorder's player leave action.
  69.  */
  70.  
  71. define tp_machines proc recorderLeave()status:
  72.     string s;
  73.  
  74.     s := o_recorder@p_recorderRecord;
  75.     if Length(s) >= 3500 then
  76.      s := "";
  77.     else
  78.     s := s + "    " + FormatName(Me()@p_pName) + " left.\n";
  79.     fi;
  80.     o_recorder@p_recorderRecord := s;
  81.     continue
  82. corp;
  83.  
  84. /* prevent players from picking up the recorder */
  85.  
  86. define tp_machines proc recorderGet(thing th)status:
  87.     Print("Sorry, but the machine is bolted to the floor!\n");
  88.     if not Me()@p_pHidden then
  89.     OPrint(FormatName(Me()@p_pName) +
  90.            " tries to pick up the enter-exit machine.\n");
  91.     fi;
  92.     fail
  93. corp;
  94.  
  95. /* play/erase functions */
  96.  
  97. define tp_machines proc recorderPlay()status:
  98.     string s;
  99.  
  100.     s := o_recorder@p_recorderRecord;
  101.     if s = "" then
  102.     Print("The machine's record is empty.\n");
  103.     else
  104.     Print("The machine's record contains:\n" + s);
  105.     fi;
  106.     if not Me()@p_pHidden then
  107.     OPrint(FormatName(Me()@p_pName) + " fiddles with the machine.\n");
  108.     fi;
  109.     succeed
  110. corp;
  111.  
  112. /* recorderErase is in tp_misc since it is needed by the Postman */
  113. define tp_misc proc recorderErase()status:
  114.     string s;
  115.  
  116.     s := FormatName(Me()@p_pName);
  117.     o_recorder@p_recorderRecord := "    " + s + " erased this record.\n";
  118.     Print("OK, the machine's record is erased.\n");
  119.     if not Me()@p_pHidden then
  120.     OPrint(s + " fiddles with the machine.\n");
  121.     fi;
  122.     succeed
  123. corp;
  124.  
  125. /* attach the functions to the room the recorder is in */
  126.  
  127. AddAnyEnterChecker(r_mallEntrance, recorderEnter, false).
  128. AddAnyLeaveChecker(r_mallEntrance, recorderLeave, false).
  129.  
  130. /* and to the recorder itself */
  131.  
  132. o_recorder@p_oGetChecker := recorderGet.
  133. o_recorder@p_oPlayChecker := recorderPlay.
  134. o_recorder@p_oEraseChecker := recorderErase.
  135.  
  136. /* Exercise for the reader: remove the limitation of the recorder not
  137.    being portable. Do it without leaving a lot of properties hanging around
  138.    that aren't being used. */
  139.  
  140.  
  141.  
  142. /* Now the true machines */
  143.  
  144.  
  145. define tp_machines p_mLastDir CreateIntProp().
  146. define tp_machines p_mWantDelay CreateBoolProp().
  147. define tp_machines p_mArrived CreateBoolProp().
  148. define tp_machines p_mCommand CreateStringProp().
  149. define tp_machines p_mWho CreateStringProp().
  150.  
  151.  
  152. /* First, Caretaker */
  153.  
  154. define tp_machines Caretaker CreateThing(nil).
  155.  
  156. /* caretakerGreet - let the caretaker greet everyone in a room he enters. */
  157.  
  158. define tp_machines proc caretakerGreet(thing who)void:
  159.     string name;
  160.  
  161.     name := who@p_pName;
  162.     if name ~= "Caretaker" then
  163.     DoSay("Good day " + FormatName(name) + "!");
  164.     fi;
  165. corp;
  166.  
  167. /* caretakerStep - the central action routine for the caretaker */
  168.  
  169. define tp_machines proc caretakerStep()void:
  170.     thing here, me, object, home;
  171.     list thing lt;
  172.     int dir, firstNum, count, n;
  173.     bool found, lost;
  174.  
  175.     if not ClientsActive() then
  176.     /* no clients (humans) are playing - do little */
  177.     After(60, caretakerStep);
  178.     else
  179.     me := Me();
  180.     if me@p_mArrived then
  181.         /* this phase - greet everyone */
  182.         me@p_mArrived := false;
  183.         ForEachAgent(Here(), caretakerGreet);
  184.         After(20, caretakerStep);
  185.     else
  186.         /* this phase - move */
  187.         me@p_mArrived := true;
  188.         firstNum := me@p_mLastDir;
  189.         if Random(3) ~= 0 then
  190.         dir := firstNum;
  191.         else
  192.         firstNum := DirBack(firstNum);
  193.         while
  194.             dir := Random(12);
  195.             dir = firstNum
  196.         do
  197.         od;
  198.         firstNum := dir;
  199.         fi;
  200.         found := false;
  201.         lost := false;
  202.         while not found do
  203.         if TryToMove(dir) then
  204.             found := true;
  205.         else
  206.             dir := (dir + 1) % 12;
  207.             if dir = firstNum then
  208.             lost := true;
  209.             found := true;
  210.             fi;
  211.         fi;
  212.         od;
  213.         if lost then
  214.         Log("Caretaker stuck, " + Here()@p_rName + "\n");
  215.         Say("", "I'm stuck! Heeeeelp!!");
  216.         After(600, caretakerStep);
  217.         else
  218.         me@p_mLastDir := dir;
  219.         MachineMove(dir);
  220.         here := Here();
  221.  
  222.         /* Go through the objects in the room we just entered. Pick
  223.            each normal object up. If the object is not where it
  224.            "belongs", then keep it, otherwise drop it right away. */
  225.         lt := here@p_rContents;
  226.         count := Count(lt);
  227.         n := 0;
  228.         while n < count do
  229.             object := lt[n];
  230.             if not object@p_oInvisible and not object@p_oNotGettable
  231.             then
  232.             /* DoGet removes an object from the list */
  233.             count := count - 1;
  234.             if DoGet(here, me, object) ~= continue then
  235.                 /* something happened - abort out */
  236.                 n := count;
  237.             else
  238.                 home := object@p_oHome;
  239.                 if home = here or home = nil then
  240.                 /* object belongs here - drop it right away */
  241.                 if DoDrop(here, me, object) ~= continue then
  242.                     /* something happened - abort out */
  243.                     n := count;
  244.                 fi;
  245.                 /* otherwise, object is put on the end of the
  246.                    contents list, and we do not need to look at
  247.                    it again. */
  248.                 fi;
  249.                 /* otherwise, he just keeps it for now */
  250.             fi;
  251.             else
  252.             n := n + 1;
  253.             fi;
  254.         od;
  255.  
  256.         /* Go through the list of stuff he is carrying. If anything
  257.            in that list "belongs" here, then drop it. */
  258.         lt := me@p_pCarrying;
  259.         count := Count(lt);
  260.         n := 0;
  261.         while n < count do
  262.             object := lt[n];
  263.             if object@p_oHome = here then
  264.             count := count - 1;
  265.             if DoDrop(here, me, object) ~= continue then
  266.                 n := count;
  267.             fi;
  268.             else
  269.             n := n + 1;
  270.             fi;
  271.         od;
  272.  
  273.         After(20, caretakerStep);
  274.         fi;
  275.     fi;
  276.     fi;
  277. corp;
  278.  
  279. /* have the caretaker do the command we want him to do */
  280.  
  281. define tp_machines proc caretakerCommand()void:
  282.     thing me;
  283.     string command;
  284.  
  285.     me := Me();
  286.     command := me@p_mCommand;
  287.     me -- p_mCommand;
  288.     ignore Parse(G, command);
  289. corp;
  290.  
  291. /* the caretaker's "understanding" of things told to him */
  292.  
  293. define tp_machines proc caretakerTold()void:
  294.     thing me;
  295.     string w, np;
  296.  
  297.     me := Me();
  298.     w := GetTail();
  299.     SetTail(w);
  300.     w := GetWord();
  301.     if w == "drop" or w == "put" or w == "p" then
  302.     /* someone is telling the caretaker to drop something */
  303.     w := GetTail();
  304.     np := GetNounPhrase(G, w, 0);
  305.     if np = "" or FindName(me@p_pCarrying, p_oName, np) ~= succeed then
  306.         /* he is not carrying something matching what they want him to
  307.            drop */
  308.         if MatchName("flashlight.light;flash", np) >= 0 then
  309.         /* there really isn't any such thing */
  310.         DoSay("No way! It's mine!");
  311.         else
  312.         OPrint("Caretaker shakes his head in confusion.\n");
  313.         fi;
  314.     else
  315.         /* He is carrying something that matches. Say 'Certainly' and
  316.            try to drop it after 1 second. */
  317.         DoSay("Certainly.");
  318.         me@p_mCommand := "drop " + w;
  319.         After(1, caretakerCommand);
  320.     fi;
  321.     else
  322.     /* Dropping things is the only thing he will do */
  323.     DoSay("Sorry, I've got my work to see to.");
  324.     fi;
  325. corp;
  326.  
  327. define tp_machines proc caretakerHear(string what)void:
  328.     string word;
  329.  
  330.     word := SetSay(what);
  331.     if word ~= "" and word ~= "Packrat" and word ~= "Caretaker" then
  332.     /* ignore things said by the packrat or by himself */
  333.     word := GetWord();
  334.     if word == "Caretaker" or word == "Caretaker," or word == "Caretaker:"
  335.     then
  336.         /* only act if the speech started with his name */
  337.         caretakerTold();
  338.     elif word == "hello" or word == "hi" then
  339.         /* minimal conversationalist! */
  340.         OPrint("Caretaker grunts an acknowledgement.\n");
  341.     fi;
  342.     fi;
  343. corp;
  344.  
  345. /* called by the system when someone whispers to him */
  346.  
  347. define tp_machines proc caretakerWhispered(string what)void:
  348.  
  349.     if SetWhisperMe(what) ~= "" then
  350.     caretakerTold();
  351.     fi;
  352. corp;
  353.  
  354. /* called as the first step of someone giving something to him */
  355.  
  356. define tp_machines proc caretakerPre()status:
  357.  
  358.     SPrint(TrueMe(), "Caretaker accepts the gift.\n");
  359.     continue
  360. corp;
  361.  
  362. /* used for several other possible actions */
  363.  
  364. define tp_machines proc caretakerNoNo()status:
  365.  
  366.     DoSay("Watch it!");
  367.     fail
  368. corp;
  369.  
  370. define tp_machines proc caretakerCreate()void:
  371.  
  372.     Caretaker@p_pStandard := true;
  373.     Caretaker@p_mLastDir := D_SOUTH;
  374.     Caretaker@p_mArrived := true;
  375.     SetupMachine(Caretaker);
  376.     Caretaker@p_pDesc :=
  377. "The caretaker is a simple soul. He wears faded overalls, a green check "
  378. "shirt, heavy work boots and a grimy cap, on backwards. His goal in life is "
  379. "to put things back where they belong. One of his most prized possessions is "
  380. "a small handheld flashlight, which he keeps securely hidden in an inside "
  381. "pocket until he needs it.";
  382.     Caretaker@p_oLight := true;
  383.     CreateMachine("Caretaker", Caretaker, r_crossSW, caretakerStep);
  384.     ignore SetMachineActive(Caretaker, caretakerStep);
  385.     ignore SetMachineSay(Caretaker, caretakerHear);
  386.     ignore SetMachineWhisperMe(Caretaker, caretakerWhispered);
  387.     GNewIcon(Caretaker, makeCaretakerIcon());
  388.     Caretaker@p_pGivePre := caretakerPre;
  389.     Caretaker@p_oTouchChecker := caretakerNoNo;
  390.     Caretaker@p_oSmellChecker := caretakerNoNo;
  391.     Caretaker@p_oPushChecker := caretakerNoNo;
  392.     Caretaker@p_oPullChecker := caretakerNoNo;
  393.     Caretaker@p_oTurnChecker := caretakerNoNo;
  394.     Caretaker@p_oLiftChecker := caretakerNoNo;
  395.     Caretaker@p_oLowerChecker := caretakerNoNo;
  396.     Caretaker@p_oEatChecker := caretakerNoNo;
  397. corp;
  398. caretakerCreate().
  399. ignore DeleteSymbol(tp_machines, "caretakerCreate").
  400.  
  401.  
  402. /* Now Packrat */
  403.  
  404. define tp_machines Packrat CreateThing(nil).
  405.  
  406. /* packratStep - the central action routine for the packrat */
  407.  
  408. define tp_machines proc packratStep()void:
  409.     thing here, me, object;
  410.     list thing lt;
  411.     int dir, firstNum, n;
  412.     bool found, lost;
  413.  
  414.     if not ClientsActive() then
  415.     After(60, packratStep);
  416.     else
  417.     me := Me();
  418.     if me@p_mWantDelay then
  419.         me@p_mWantDelay := false;
  420.         After(10 + Random(20), packratStep);
  421.         me@p_mArrived := true;
  422.     elif me@p_pPosition ~= 0 then
  423.         ignore Parse(G, "stand up");
  424.         After(10 + Random(20), packratStep);
  425.     elif me@p_mArrived then
  426.         me@p_mArrived := false;
  427.         if Here() = r_pearField then
  428.         if FindName(me@p_pCarrying, p_oName, "pear") ~= fail then
  429.             ignore Parse(G, "eat pear");
  430.         else
  431.             ignore Parse(G, "pick pear");
  432.             me@p_mArrived := true;
  433.         fi;
  434.         fi;
  435.         After(10 + Random(20), packratStep);
  436.     else
  437.         me@p_mArrived := true;
  438.         firstNum := me@p_mLastDir;
  439.         if Random(2) ~= 0 then
  440.         dir := firstNum;
  441.         else
  442.         firstNum := DirBack(firstNum);
  443.         while
  444.             dir := Random(12);
  445.             dir = firstNum
  446.         do
  447.         od;
  448.         firstNum := dir;
  449.         fi;
  450.         found := false;
  451.         lost := false;
  452.         while not found do
  453.         if TryToMove(dir) then
  454.             found := true;
  455.         else
  456.             dir := (dir + 1) % 12;
  457.             if dir = firstNum then
  458.             lost := true;
  459.             found := true;
  460.             fi;
  461.         fi;
  462.         od;
  463.         if lost then
  464.         Log("Packrat is stuck, " + Here()@p_rName + "\n");
  465.         Say("", "I'm stuck! Waaaahhhh!!");
  466.         After(600, packratStep);
  467.         else
  468.         me@p_mLastDir := dir;
  469.         MachineMove(dir);
  470.         here := Here();
  471.         lt := here@p_rContents;
  472.         n := Count(lt);
  473.         if n ~= 0 then
  474.             object := lt[Random(n)];
  475.             if not object@p_oInvisible and not object@p_oNotGettable
  476.             then
  477.             if DoGet(here, me, object) = continue then
  478.                 lt := me@p_pCarrying;
  479.                 n := Count(lt);
  480.                 if n = 4 then
  481.                 ignore DoDrop(here, me, lt[Random(3)]);
  482.                 fi;
  483.             fi;
  484.             fi;
  485.         else
  486.             lt := me@p_pCarrying;
  487.             n := Count(lt);
  488.             if n ~= 0 and Random(20) = 0 then
  489.             ignore DoDrop(here, me, lt[Random(n)]);
  490.             fi;
  491.         fi;
  492.         After(10 + Random(20), packratStep);
  493.         fi;
  494.     fi;
  495.     fi;
  496. corp;
  497.  
  498. /*
  499.  * This kind of delay is a wise thing to do, since it avoids many possible
  500.  *    cases of recursion that could be troublesome. Consider the possibility
  501.  *    of multiple packrat's in one room, and someone waves...
  502.  */
  503.  
  504. define tp_machines proc packratCommand()void:
  505.     thing me;
  506.     string command, who;
  507.  
  508.     me := Me();
  509.     who := me@p_mWho;
  510.     if who ~= "" then
  511.     SetMeString(who);
  512.     me -- p_mWho;
  513.     fi;
  514.     command := me@p_mCommand;
  515.     me -- p_mCommand;
  516.     SetTail(command);
  517.     if GetWord() == "pose" then
  518.     Pose("", GetTail());
  519.     else
  520.     if Parse(G, command) = 0 then
  521.         DoSay("Sorry luv, you've confused me.");
  522.     fi;
  523.     fi;
  524. corp;
  525.  
  526. define tp_machines proc packratTold()void:
  527.     thing me;
  528.     string command;
  529.     int direction;
  530.  
  531.     me := Me();
  532.     /* need to save the tail, since doing 'DoSay' can change it! */
  533.     command := GetTail();
  534.     me@p_mWantDelay := true;
  535.     DoSay("Right you are luv.");
  536.     direction := DirMatch(command);
  537.     if direction ~= -1 then
  538.     me@p_mLastDir := direction;
  539.     fi;
  540.     me@p_mCommand := command;
  541.     After(1, packratCommand);
  542. corp;
  543.  
  544. define tp_machines proc packratHear(string what)void:
  545.     string word;
  546.  
  547.     word := SetSay(what);
  548.     if word ~= "" and word ~= "Packrat" and word ~= "Caretaker" then
  549.     Me()@p_mWho := word;
  550.     word := GetWord();
  551.     if word == "Packrat" or word == "Packrat," or word == "Packrat:" then
  552.         packratTold();
  553.     elif word == "hello" or word == "hi" or word == "greetings" then
  554.         DoSay(word + " to you too, luv!");
  555.     elif word == "good" or word == "nice" then
  556.         word := GetWord();
  557.         DoSay("You have a good'n too luv!");
  558.     fi;
  559.     fi;
  560. corp;
  561.  
  562. define tp_machines proc packratWhispered(string what)void:
  563.     string who;
  564.  
  565.     who := SetWhisperMe(what);
  566.     if who ~= "" then
  567.     Me()@p_mWho := who;
  568.     packratTold();
  569.     fi;
  570. corp;
  571.  
  572. define tp_machines proc packratOverhear(string what)void:
  573.     string who, target;
  574.  
  575.     who := SetWhisperOther(what);
  576.     if who ~= "" then
  577.     target := GetWord();
  578.     if target ~= "" then
  579.         what := GetTail();
  580.         if what ~= "" then
  581.         DoSay("Luv, if you want " + target + " to " + what +
  582.             ", you'd better speak up!");
  583.         fi;
  584.     fi;
  585.     fi;
  586. corp;
  587.  
  588. define tp_machines proc packratSaw(string what)void:
  589.  
  590.     SetTail(what);
  591.     ignore GetWord();
  592.     what := GetTail();
  593.     Me()@p_mCommand := "pose " + what;
  594.     After(1, packratCommand);
  595. corp;
  596.  
  597. define tp_machines proc packratNoNo()status:
  598.  
  599.     DoSay("'ere now - don't get fresh w' me!");
  600.     fail
  601. corp;
  602.  
  603. /* This is needed so that Packrat can thank you AFTER you have seen the
  604.    message about giving. */
  605.  
  606. define tp_machines proc packratThank()void:
  607.  
  608.     DoSay("ta, luv!");
  609. corp;
  610.  
  611. define tp_machines proc packratPost()status:
  612.  
  613.     After(1, packratThank);
  614.     continue
  615. corp;
  616.  
  617. define tp_machines proc packratCreate()void:
  618.  
  619.     Packrat@p_pStandard := true;
  620.     Packrat@p_mLastDir := D_SOUTH;
  621.     Packrat@p_mArrived := false;
  622.     SetupMachine(Packrat);
  623.     Packrat@p_pQuestDoneList := CreateThingList();
  624.     Packrat@p_pDesc :=
  625. "The packrat is a small woman with a wizened face, stringy brown hair, and "
  626. "beady little eyes. She is wearing a very old blue dress and an indeterminate "
  627. "number of sweaters. A battered felt hat with a drab daisy perches "
  628. "precariously on her head.";
  629.     CreateMachine("Packrat", Packrat, r_es2, packratStep);
  630.     ignore SetMachineActive(Packrat, packratStep);
  631.     ignore SetMachineSay(Packrat, packratHear);
  632.     ignore SetMachineWhisperMe(Packrat, packratWhispered);
  633.     ignore SetMachineWhisperOther(Packrat, packratOverhear);
  634.     ignore SetMachinePose(Packrat, packratSaw);
  635.     GNewIcon(Packrat, makePackratIcon());
  636.     Packrat@p_pGivePost := packratPost;
  637.     Packrat@p_oTouchChecker := packratNoNo;
  638.     Packrat@p_oSmellChecker := packratNoNo;
  639.     Packrat@p_oPushChecker := packratNoNo;
  640.     Packrat@p_oPullChecker := packratNoNo;
  641.     Packrat@p_oTurnChecker := packratNoNo;
  642.     Packrat@p_oLiftChecker := packratNoNo;
  643.     Packrat@p_oLowerChecker := packratNoNo;
  644.     Packrat@p_oEatChecker := packratNoNo;
  645. corp;
  646. packratCreate().
  647. ignore DeleteSymbol(tp_machines, "packratCreate").
  648.  
  649. unuse tp_machines
  650. unuse t_streets
  651.